package com.systemframework.aspect;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.alibaba.fastjson.JSON;
import com.systemframework.annotation.OperateAnnotation;
import com.systemframework.constants.Constants;
import com.systemframework.sys.entity.SysOperate;
import com.systemframework.sys.service.SysOperateService;
import com.systemframework.util.IpKit;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * @author summer
 * @date 2024-09-20
 */
@Component
@Aspect
@Slf4j
@Order(1)
public class OperateAspect {

    private SysOperateService sysOperateService;

    @Autowired
    public void setSysOperateService(SysOperateService sysOperateService) {
        this.sysOperateService = sysOperateService;
    }

    private Long startTime=null;

    @Before(value = "@annotation(com.systemframework.annotation.OperateAnnotation)")
    public void before(){
        startTime= DateUtil.current();
        log.info("开始执行时间:{}",startTime);
    }

    /**
     * 成功
     * @param joinPoint
     * @param ret
     */
    @AfterReturning(value = "@annotation(com.systemframework.annotation.OperateAnnotation)",returning = "ret")
    public void aroundAspect(JoinPoint joinPoint,Object ret){
        SysOperate sysOperate = sysOperate(joinPoint);
        sysOperate.setTime(System.currentTimeMillis()-startTime);
        sysOperate.setReturnMsg(Constants.SUCCESS);
        sysOperateService.save(sysOperate);
    }

    /**
     * 失败
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(value = "@annotation(com.systemframework.annotation.OperateAnnotation)",throwing = "ex")
    public void afterThrow(JoinPoint joinPoint,Exception ex){
        SysOperate sysOperate = sysOperate(joinPoint);
        sysOperate.setTime(System.currentTimeMillis()-startTime);
        sysOperate.setReturnMsg(Constants.FAIl);
        sysOperate.setEx(ex.getLocalizedMessage());
        sysOperateService.save(sysOperate);
    }

     public SysOperate sysOperate(JoinPoint joinPoint)  {
        HttpServletRequest request = Convert.convert(ServletRequestAttributes.class, RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = IpKit.getRealIp(request);
        UserAgent userAgent = UserAgentUtil.parse(request.getHeader(Constants.USER_AGENT));
        String browserName = userAgent.getBrowser().toString();
        Signature signature = joinPoint.getSignature();
        String methodName = signature.getName();
        MethodSignature methodSignature = Convert.convert(MethodSignature.class, signature);
        Method method = methodSignature.getMethod();
        OperateAnnotation annotation = method.getAnnotation(OperateAnnotation.class);
        Object[] args = joinPoint.getArgs();
        List<Object> objects = Arrays.asList(args);
        SysOperate sysOperate = new SysOperate();
        sysOperate.setIp(ip);
        sysOperate.setMethodName(methodName);
        sysOperate.setUserAgent(browserName);
        sysOperate.setModelName(annotation.name());
        sysOperate.setOperateMessage(annotation.businessType().getMsg());
        sysOperate.setUserId(StpUtil.getLoginIdAsInt());
        sysOperate.setParams(JSON.toJSONString(objects));
        return sysOperate;
    }
}
